#include "common.h"
#define BUFFSIZE 1024

void CMD_CD(const char *dname);
void CMD_LS(const char *dname);
void CMD_PWD();
void CMD_PUTS(const char *name);
void CMD_GETS(const char *name);
void CMD_RM(const char *name);
void RmDir(const char *dname);
void RmFile(const char *fname);
void CMD_MKDIR(const char *dname, mode_t mode);

void CMD_CD(const char *dname) {
	//暂时想不出来如何实现
	printf(">> Start CD.\n");
	int ret = chdir(dname);
	ERROR_CHECK(ret, -1, "chdir");
	printf(">> Finish CD.\n");
}


void CMD_LS(const char *dname) {
	printf(">> Start LS.\n");

	DIR *pdir = NULL;
	if (dname == NULL) {
		pdir = opendir(".");
		ERROR_CHECK(pdir, NULL, "opendir");

	}
	else {
		struct stat statbuf;
		int ret = stat(dname, &statbuf);
		ERROR_CHECK(ret, -1, "stat");

		if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
			printf("%s\n", dname);
			printf(">> Finish LS.\n");
			exit(0);
		}
		else {
			pdir = opendir(dname);
			ERROR_CHECK(pdir, NULL, "opendir");
		}
	}

	struct dirent *pdirent;
	struct stat statbuf;
	errno = 0;
	while ((pdirent = readdir(pdir)) != NULL) {
		if (errno != 0) {
			perror("readdir");
			closedir(pdir);
			exit(1);
		}
		//忽略隐藏文件和隐藏文件夹
		char *name = pdirent->d_name;
		if (name[0] == '.') {
			continue;
		}

		char pathname[BUFFSIZE];
		if (dname == NULL) {
			char path[BUFFSIZE] = { 0 };
			char *cwd = getcwd(path, SIZE(path));
			sprintf(pathname, "%s/%s", cwd, name);
		}
		else {
			sprintf(pathname, "%s/%s", dname, name);
		}

		int ret = stat(pathname, &statbuf);
		if (ret == -1) {
			closedir(pdir);
			perror("stat");
			exit(1);
		}

		//打印inode信息
		printf("%lu\t", statbuf.st_ino);

		//打印类型信息
		switch (statbuf.st_mode & S_IFMT) {
			//case S_IFBLK:
			//    printf("b");
			//    break;
			//case S_IFCHR:
			//    printf("c");
			//    break;
		case S_IFDIR:
			printf("目录文件  ");
			break;
			//case S_IFIFO:
			//    printf("p");
			//    break;
			//case S_IFLNK:
			//    printf("l");
			//   break;
		case S_IFREG:
			printf("普通文件  ");
			break;
			//case S_IFSOCK:
			//    printf("s");
			//    break;
		default:
			break;
		}
#if 0
		//打印权限信息
		//位图，三位是一组，右移动6位是u，右移3位是g，不右移动是o
		for (int i = 0; i < 3; ++i) {
			int m = (statbuf.st_mode >> 3 * (2 - i));
			switch (m) {
			case 0:		printf("---");		break;
			case 1:		printf("--x");		break;
			case 2:		printf("-w-");		break;
			case 3:		printf("-wx");		break;
			case 4:		printf("r--");		break;
			case 5:		printf("r-x");		break;
			case 6:		printf("rw-");		break;
			default:	printf("rwx");		break;
			}
		}
		printf(" ");

		//打印硬链接数目
		printf("%3ld ", statbuf.st_nlink);

		//根据uid打印用户名字
		struct passwd* pwd = getpwuid(statbuf.st_uid);
		if (errno != 0) {
			perror("getpwuid");
			closedir(pdir);
			exit(1);
		}
		printf("%s ", pwd->pw_name);

		//根据gid打印组名称
		struct group* grp = getgrgid(statbuf.st_gid);
		if (errno != 0) {
			perror("getgrgid");
			closedir(pdir);
			exit(1);
		}
		printf("%s ", grp->gr_name);
#endif
		//打印文件大小
		printf("%8ld ", statbuf.st_size);

		//处理时间：把表示时间的数字，转化成字符串
		struct tm *ptime = localtime(&statbuf.st_atime);
		ERROR_CHECK(ptime, NULL, "localtime");

		printf("%d/%.2d/%.2d %.2d:%.2d:%.2d ",
			ptime->tm_year + 1900,
			ptime->tm_mon + 1,
			ptime->tm_mday,
			ptime->tm_hour,
			ptime->tm_min,
			ptime->tm_sec);

		//打印文件名
		puts(name);
		}
	closedir(pdir);
	printf(">> Finish LS.\n");
}


void CMD_PWD() {
	printf(">> Start PWD.\n");
	char *cwd = getcwd(NULL, 0);
	printf("%s\n", cwd);
	free(cwd);
	printf(">> Finish PWD.\n");
}

void CMD_PUTS(const char *name) {

}
void CMD_GETS(const char *name) {


}



//删除文件
void CMD_RM(const char *name) {
	printf(">> Start RM.\n");
	struct stat statbuf;
	int ret = stat(name, &statbuf);
	ERROR_CHECK(ret, -1, "stat");

	if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
		//注意把文件夹内的文件删除后还要删除文件夹本身
		RmDir(name);
		rmdir(name);
	}
	else {
		RmFile(name);
	}
	printf(">> Finish RM.\n");
}

void RmDir(const char *dname) {
	DIR *pdir = opendir(dname);
	ERROR_CHECK(pdir, NULL, "opendir");

	struct dirent *pdirent;
	struct stat statbuf;
	errno = 0;
	while ((pdirent = readdir(pdir)) != NULL) {
		if (errno != 0) {
			closedir(pdir);
			perror("readdir");
			exit(1);
		}
		//忽略上级目录和本级目录，不忽略会一直出错
		char *name = pdirent->d_name;
		if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) {
			continue;
		}

		//拼接文件名，避免在本文件夹中无法删除其他文件夹现象出现
		char pathname[1024];
		sprintf(pathname, "%s/%s", dname, name);

		int ret = stat(pathname, &statbuf);
		if (ret == -1) {
			closedir(pdir);
			perror("stat");
			exit(1);
		}

		//注意要使用文件的绝对路径进行删除
		if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
			RmDir(pathname);
			rmdir(pathname);
		}
		else {
			RmFile(pathname);
		}
	}
	closedir(pdir);
}

void RmFile(const char *fname) {
	int ret = remove(fname);
	ERROR_CHECK(ret, -1, "remove");
}

void CMD_MKDIR(const char *dname, mode_t mode) {
	int ret = mkdir(dname, mode);
	ERROR_CHECK(ret, -1, "mkdir");
}
